#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <relayer.h>
#include <pthread.h>


#define TTY1  "/dev/tty11"
#define TTY2  "/dev/tty12"
#define BUFSIZE 1024

//设计当前操作的数据结构
enum {
    STATE_R = 1,     //读
    STATE_W,         //写
    STATE_Ex,        //异常
    STATE_T          //终止？
};
struct rel_fsm_st
{
    /* data */
    int state;  //当前状态机的状态
    int sfd;
    int dfd;
    char buf[BUFSIZE];
    int len;
    int pos;   //记录读取到的字符是否完全写入
    char *errstr ;   // 记录出错的原因
    int64_t count;   //记录写了多少字段
};
struct rel_job_st
{
    int job_state;
    int fd1;
    int fd2;
    struct rel_fsm_st fsm12,fsm21;
    int fd1_save,fd2_save;
    //时间戳

};
static struct rel_job_st * rel_job[REL_JOBMAX];
static pthread_mutex_t mut_rel_job = PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;

static void fsm_driver (struct rel_fsm_st *fsm){
    int ret;
    switch(fsm->state){
        case STATE_R:         //读态，要做的操作
            fsm->len = read(fsm->sfd,fsm->buf,BUFSIZ);  //读数据
            if(fsm->len == 0){                          //没有数据，跳到终止态
                fsm->state = STATE_T;
            }
            else if(fsm->len < 0){                      //小于0 错误，判断errno 是真错还是假错
                if(errno == EAGAIN)
                    fsm->state = STATE_R;               // 假错，再去读
                else{
                    fsm->errstr = "read()";
                    fsm->state = STATE_Ex;              //真错，去往异常终止
                }
                    
            }
            else{
                fsm->pos = 0;
                fsm->state = STATE_W;                    //读到数据，跳到写态
            }
            break;
        case STATE_W:
            ret = write(fsm->dfd,fsm->buf+fsm->pos,fsm->len);  
            if(ret < 0){
                if (errno == EAGAIN)
                    fsm->state = STATE_W;
                else {
                    fsm->errstr = "write()";
                    fsm->state = STATE_Ex;
                }
                    
            }
            else{
                fsm-> pos += ret;
                fsm->len -= ret;     //判断当前是否写够了len个字符 
                if(fsm->len  == 0)
                    fsm->state = STATE_R;
                else
                    fsm->state = STATE_W;
            }
            break;
        case STATE_Ex:
            perror(fsm->errstr);
            fsm->state = STATE_T;   //异常处理的结果肯定是将状态推向终止态
            break;
        case STATE_T:          
            /*do somethine*/
            break;
        default:
        /*do somethine*/
            abort();
            break;

    }
}

static int relay(int fd1, int fd2){
    //确保两个设备的文件描述符都是非阻塞状态
    int fd1_save,fd2_save;                   //存储文件状态
    fd1_save = fcntl(fd1,F_GETFL);           //存储当前的文件状态
    fcntl(fd1,F_SETFL,fd1_save|O_NONBLOCK);  //或上非阻塞，设置文件的状态
    fd2_save = fcntl(fd2,F_GETFL);           
    fcntl(fd2,F_SETFL,fd2_save|O_NONBLOCK);  

    struct fsm_st  fsm12,fsm21;            //读左写右  和 读右写左的两个现场
    //*********初始化***********//
    fsm12.state = STATE_R;
    fsm12.sfd = fd1;
    fsm12.dfd = fd2;
    fsm21.state = STATE_R;
    fsm21.sfd = fd2;
    fsm21.dfd = fd1;
     
    while(fsm12.state != STATE_T ||fsm21.state != STATE_T ){  //当两个状态机都不是终止状态时，驱动开始
        fsm_driver(&fsm12);   //传指针
        fsm_driver(&fsm21);
    }

    fcntl(fd1,F_SETFL,fd1_save);     //保证进模块和出模块状态不变，恢复原来的读写状态
    fcntl(fd2,F_SETFL,fd2_save);


}
static void*thr_relayer(void*p){
    while(1){
        pthread_mutex_lock();
        for(int i = O;i < REL_JOBMAX;i++){
            if(rel_job[i]!= NULL){
                if(rel_job[i]->job_state == STATE_RUNNING){
                    
                            fsm_driver(&rel_job[i] ->fsm12); 
                            fsm_driver(&rel_job[i] ->fsm21);
                            if (rel_job[i]->fsm12. state != STATE_T && \
                        rel_job[i]->fsm21. state != STATE_T){
                            rel_job[i]->job_state = STATE_OVER;
                        }
                    
                }
                
            }
        }      
        pthread_mutex_unlock();
    }
    
    
}

//module_unload();
static void module_load (void){
    pthread_t tid_relayer;
    int err; 
    err = pthread_create (&tid_relayer, NULL, thr_relayer, NULL); 
    if(err){
        fprintf (stderr, "pthread_create() :%s\n", strerror(err)); 
        exit (1);
    }

}
int get_free_pos_unlocked (){
    int i;
    for(i=0;i < REL_JOBMAX; i++){
        if (rel_job[i] == NULL)
            return i;
    }   
    return -1;
}

/*rel_addjob
*return  0  >=0 成功，返回当前任务的ID
*           == -EINVAL  失败，参数非法
*           == -ENOSPC   失败，任务数组满
*           == -ENOMEM   失败，内存分配有误
*/
int rel_addjob(int fd1,int fd2)   //向数组中添加任务
{
    struct rel_job_st *me;
    pthread_once (&init_once, module_load);
    int pos;
    me = malloc(sizeof(*me));
    if(me == NULL){
        return -ENOMEM;
    }
    me -> fd1 = fd1;
    me -> fd2 = fd2;
    me -> job_state = STATE_RUNING;

    me ->fd1_save = fcntl(me->fd1,F_GETFL);
    fcntl(me->fd1,F_SETFL,fd1_save|O_NONBLOCK);
     me ->fd2_save = fcntl(me->fd2,F_GETFL);
    fcntl(me->fd2,F_SETFL,fd2_save|O_NONBLOCK);

    me->fsm12.sfd = me->fd1;
    me->fsm12.dfd = me->fd2;
    me->fsm12.state = STATE_R;

    me->fsm21.sfd = me->fd2;
    me->fsm21.dfd = me->fd1;
    me->fsm21.state = STATE_R;

   pthread_mutex_Lock (&mut_rel_job); 
   pos = get_free_pos_unlocked (); 
   if (pos < 0){
       pthread_mutex_unlock (&mut_rel_job);
       fcntl (me->fdl, F_SETFL, me->fdl_save);
       fcntl (me->fd2, F_SETFL, me->fd2_save); 
       free(me);
       return -ENOSPC;
   }
   rel_job[pos] = me;
   pthread_mutex_unlock (&mut_rel_job);
   return pos;
}
/* rel_canceljob
*return     ==  0        成功，指定任务取消
*           == -EINVAL  失败，参数非法
*           == -EBUSY   失败，任务早已取消
*/
int rel_canceljob(int id);        //取消任务
{

}

/*
*return    ==  0        成功，指定任务已终止并返回状态
*           == -EINVAL  失败，参数非法
*           
*/
int rel_waitjob(int id,struct rel_stat_st *)       //等待任务结束，收尸
{

}
/*
*return  0  ==  0        成功，指定任务状态已回填
*           == -EINVAL  失败，参数非法
*            
*/
int rel_statjob(int id,struct rel_stat_st *)        //获得任务的状态
{

}

 